package com.sitech.ibnms.c3p.rest;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.sitech.ibnms.c3p.command.CommandType;
import com.sitech.ibnms.c3p.domain.ResourceAccount;
import com.sitech.ibnms.c3p.service.ScriptExecutor;
import com.sitech.ismp.messageObject.cc.CccpResults;
import com.sitech.ismp.workflow.util.DES3;
import lombok.Data;
import lombok.SneakyThrows;
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.Range;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import request.ScriptRequest;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * Created by leo on 16/6/2.
 */
@RestController
public class ScriptExecutorController {
    @Autowired
    private ScriptExecutor executor;
    @Autowired
    private ObjectMapper objectMapper;

    public static class ScriptExecutorRequest
    {
        @NotBlank
        private String script;

        public void setScript(String script)
        {
            this.script = script;
        }

        public void setInputVars(Map<String, String> inputVars)
        {
            this.inputVars = inputVars;
        }

        public void setOutputVars(List<String> outputVars)
        {
            this.outputVars = outputVars;
        }

        public void setHost(String host)
        {
            this.host = host;
        }

        public void setPort(int port)
        {
            this.port = port;
        }

        public void setUsername(String username)
        {
            this.username = username;
        }

        public void setPassword(String password)
        {
            this.password = password;
        }

        public boolean equals(Object o)
        {
            if (o == this) {
                return true;
            }
            if (!(o instanceof ScriptExecutorRequest)) {
                return false;
            }
            ScriptExecutorRequest other = (ScriptExecutorRequest)o;
            if (!other.canEqual(this)) {
                return false;
            }
            Object this$script = getScript();Object other$script = other.getScript();
            if (this$script == null ? other$script != null : !this$script.equals(other$script)) {
                return false;
            }
            Object this$inputVars = getInputVars();Object other$inputVars = other.getInputVars();
            if (this$inputVars == null ? other$inputVars != null : !this$inputVars.equals(other$inputVars)) {
                return false;
            }
            Object this$outputVars = getOutputVars();Object other$outputVars = other.getOutputVars();
            if (this$outputVars == null ? other$outputVars != null : !this$outputVars.equals(other$outputVars)) {
                return false;
            }
            Object this$host = getHost();Object other$host = other.getHost();
            if (this$host == null ? other$host != null : !this$host.equals(other$host)) {
                return false;
            }
            if (getPort() != other.getPort()) {
                return false;
            }
            Object this$username = getUsername();Object other$username = other.getUsername();
            if (this$username == null ? other$username != null : !this$username.equals(other$username)) {
                return false;
            }
            Object this$password = getPassword();Object other$password = other.getPassword();return this$password == null ? other$password == null : this$password.equals(other$password);
        }

        protected boolean canEqual(Object other)
        {
            return other instanceof ScriptExecutorRequest;
        }

        public int hashCode()
        {
            int PRIME = 59;int result = 1;Object $script = getScript();result = result * 59 + ($script == null ? 43 : $script.hashCode());Object $inputVars = getInputVars();result = result * 59 + ($inputVars == null ? 43 : $inputVars.hashCode());Object $outputVars = getOutputVars();result = result * 59 + ($outputVars == null ? 43 : $outputVars.hashCode());Object $host = getHost();result = result * 59 + ($host == null ? 43 : $host.hashCode());result = result * 59 + getPort();Object $username = getUsername();result = result * 59 + ($username == null ? 43 : $username.hashCode());Object $password = getPassword();result = result * 59 + ($password == null ? 43 : $password.hashCode());return result;
        }

        public String toString()
        {
            return "ScriptExecutorController.ScriptExecutorRequest(script=" + getScript() + ", inputVars=" + getInputVars() + ", outputVars=" + getOutputVars() + ", host=" + getHost() + ", port=" + getPort() + ", username=" + getUsername() + ", password=" + getPassword() + ")";
        }

        public String getScript()
        {
            return this.script;
        }

        @NotNull
        private Map<String, String> inputVars = Collections.emptyMap();

        public Map<String, String> getInputVars()
        {
            return this.inputVars;
        }

        @NotNull
        private List<String> outputVars = Collections.emptyList();
        @NotBlank
        private String host;

        public List<String> getOutputVars()
        {
            return this.outputVars;
        }

        public String getHost()
        {
            return this.host;
        }

        @Range(max=22L, min=22L)
        private int port = 22;
        @NotBlank
        @Pattern(regexp="([a-z_][a-z0-9_\\-]{0,30})", flags={javax.validation.constraints.Pattern.Flag.CASE_INSENSITIVE}, message="not a valid username")
        private String username;

        public int getPort()
        {
            return this.port;
        }

        public String getUsername()
        {
            return this.username;
        }

        @NotNull
        private String password = "";

        public String getPassword()
        {
            return this.password;
        }
    }

    //@RequestBody拿到request body里的json数据并转为ScriptExecutorRequest对象，
    //@Validated校验ScriptExecutorRequest对象里的参数是否符合条件
    @SneakyThrows
    @RequestMapping(value = "/executor/shell", method = RequestMethod.POST)
    public CccpResults executeShell(@RequestBody @Validated ScriptExecutorRequest request) {
        System.out.println("request = " + request);
        ScriptRequest scriptRequest = new ScriptRequest();
        scriptRequest.setScriptType(CommandType.SHELL.getScriptType());
        scriptRequest.setContent(request.getScript());
        try {
            scriptRequest.setInputVars(objectMapper.writeValueAsString(request.getInputVars()));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        ObjectNode objectNode = objectMapper.createObjectNode();
        for (String varName : request.getOutputVars()) {
            objectNode.put(varName, "");
        }
        scriptRequest.setOutputVars(objectNode.toString());
        scriptRequest.setRequestId("shell-" + request.hashCode());

        ResourceAccount resourceAccount = new ResourceAccount();
        resourceAccount.setIpAddr(request.getHost());
        resourceAccount.setUserName(request.getUsername());
        resourceAccount.setPassword(DES3.encrypt(request.getPassword()));
        return executor.executeScript(scriptRequest, resourceAccount, Collections.<String, String>emptyMap());
    }
}
